# Django imports
from django.http import HttpResponseBadRequest

# AppEngine imports
from google.appengine.ext import db

# Local imports
import views
import logging
import models

# Helpers

def migrate_model(request, model, key_name, callback=None):
  """
  Iterates over the database instances of a specified model, calling a callback
  for each one.
  """
  key_value = request.GET.get(key_name, None)
  if key_value is None:
    obj = model.gql("ORDER BY %s ASC" % key_name).get()
    if obj is None:
      return views.respond(request, "migrations.html")
    elif key_name == "__key__":
      key_value = str(obj.key())
    else:
      key_value = getattr(obj, key_name)
  
  if key_name == "__key__":
    key_value = db.Key(key_value)
    
  query = model.gql("WHERE %s >= :1 ORDER BY %s ASC" % (key_name, key_name), 
      key_value)
  objs = query.fetch(limit=2)
  current_obj = objs[0]
  if len(objs) == 2:
    if key_name == "__key__":
      next_key_value = str(objs[1].key())
    else:
      next_key_value = getattr(objs[1], key_name)
    next_url = "%s?%s=%s" % (request.build_absolute_uri(request.path), key_name, 
        next_key_value)
  else:
    next_key_value = "FINISHED"
    next_url = None
    
  base_data = { 
      "current_key_value" : key_value,
      "next_key_value" : next_key_value,
      "next_url" : next_url,
  }
  
  if callable(callback):
    item_data = callback(current_obj)
    if hasattr(item_data, "update"):
      base_data.update(item_data)
  
  return views.respond(request, "migrations.html", base_data)
  
@views.admin_required
def migrate(request, model=None):
  if model is None or model == "":
    return views.respond(request, "migrations.html")
  elif model == "developername":
    return migrate_model(request, DeveloperName, "opensocial_id",
        developername_to_ddopensocialaccount)
  elif model == "codesample":
    return migrate_model(request, CodeSample, "__key__",
        codesample_to_ddjavascriptcodesample)
  elif model == "xmlspec":
    return migrate_model(request, XmlSpec, "__key__",
        xmlspec_to_ddxmlspec)
  else: 
    return HttpResponseBadRequest("This was an invalid request.")
  
def _get_acct(opensocial_id, name=None):
  container, junk, id_number = opensocial_id.rpartition(":")
  acct = models.ddOpenSocialAccount.get_or_insert(container, id_number, name)
  db.put(acct)
  return acct
  
class Developer(db.Model):
  name = db.StringProperty()
  opensocial_ids = db.StringListProperty()
    
class DeveloperName(db.Model):
  name = db.StringProperty()
  opensocial_id = db.StringProperty()

def developername_to_ddopensocialaccount(data):
  _get_acct(data.opensocial_id, data.name)
  
class CodeSample(db.Model):
  name = db.StringProperty(default = "Unnamed sample")
  updated = db.DateTimeProperty(auto_now = True)
  developer = db.ReferenceProperty(Developer)
  text = db.TextProperty()
  description = db.TextProperty(default = "")
  is_global_snippet = db.BooleanProperty(default = False);

def codesample_to_ddjavascriptcodesample(data):
  opensocial_id = data.developer.opensocial_ids[0]
  acct = _get_acct(opensocial_id, data.developer.name)
  obj = models.ddJavaScriptCodeSample.get_or_insert(acct.developer, data.name)
  obj.text = data.text
  obj.description = data.description
  obj.is_global = data.is_global_snippet
  db.put(obj)

class XmlSpec(db.Model):
  name = db.StringProperty(default = "Unnamed spec")
  updated = db.DateTimeProperty(auto_now = True)
  developer = db.ReferenceProperty(Developer)
  text = db.TextProperty()
  
def xmlspec_to_ddxmlspec(data):
  opensocial_id = data.developer.opensocial_ids[0]
  acct = _get_acct(opensocial_id, data.developer.name)
  obj = models.ddXmlSpec.get_or_insert(acct.developer, data.name)
  obj.text = data.text
  db.put(obj)